package com.flux.core.dispatcher;

import android.os.Handler;
import android.os.Looper;
import android.os.Process;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;


/**
 * 任务调度器
 * Created by chenxunlin01 on 2017/10/12.
 */

public class DispatcherBackgroundExecutor implements BackgroundExecutor {

    private static final Handler sHandler = new Handler(Looper.getMainLooper());
    private final ExecutorService mExecutorService;

    public DispatcherBackgroundExecutor() {
        final int numberCores = Runtime.getRuntime().availableProcessors();
        mExecutorService = Executors.newFixedThreadPool(numberCores * 2 + 1);
    }

    @Override
    public <R> void execute(NetworkCallRunnable<R> runnable) {
        mExecutorService.execute(new FluxNetworkRunner(runnable));
    }

    @Override
    public <R> void execute(BackgroundCallRunnable<R> runnable) {
        mExecutorService.execute(new BackgroundCallRunner(runnable));
    }

    private class BackgroundCallRunner<R> implements Runnable {

        private final BackgroundCallRunnable<R> mBackgroundRunnable;

        public BackgroundCallRunner(BackgroundCallRunnable<R> backgroundRunnable) {
            this.mBackgroundRunnable = backgroundRunnable;
        }

        @Override
        public void run() {
            Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);

            sHandler.post(new Runnable() {
                @Override
                public void run() {
                    mBackgroundRunnable.preExecute();
                }
            });

            R result = mBackgroundRunnable.runAsync();

            sHandler.post(new ResultCallback(result));
        }

        private class ResultCallback implements Runnable {
            private final R mResult;

            private ResultCallback(R result) {
                mResult = result;
            }

            @Override
            public void run() {
                mBackgroundRunnable.postExecute(mResult);
            }
        }
    }

    class FluxNetworkRunner<R> implements Runnable {

        private final NetworkCallRunnable<R> mBackgroundRunnable;

        public FluxNetworkRunner(NetworkCallRunnable<R> runnable) {
            this.mBackgroundRunnable = runnable;
        }

        @Override
        public void run() {
            Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);

            sHandler.post(new Runnable() {
                @Override
                public void run() {
                    mBackgroundRunnable.onPreTraktCall();
                }
            });

            R result = null;
            Exception error = null;
            try {
                result = mBackgroundRunnable.doBackgroundCall();
            } catch (Exception e) {
                error = e;
            }

            sHandler.post(new ResultCallback(result, error));
        }

        private class ResultCallback implements Runnable {
            private final R mResult;
            private final Exception mError;

            public ResultCallback(R result, Exception error) {
                this.mResult = result;
                this.mError = error;
            }

            @Override
            public void run() {
                if (mResult != null) {
                    mBackgroundRunnable.onSuccess(mResult);
                } else if (mError != null) {
                    mBackgroundRunnable.onError(mError);
                }
                mBackgroundRunnable.onFinished();
            }
        }
    }

}
